﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Display;

namespace ZJGIS.DataConvert.model
{
    /// <summary>
    /// 导出E00
    /// </summary>
    public class E00Export
    {

        [DllImport("\\dll\\DIT.dll")]
        private static extern void ExpE00(IFeatureWorkspace pFws, string strFClassName, IQueryFilter pQf, string strPath);
        private IFeatureLayer mFeatureLayer;
        private IGeometry mFilterGeometry;
        private string mStrFiter;
        private bool mBlnClip;
        private string mStrPath;
        private string mStrE00FileName;
        private IFeatureWorkspace mTempWks;
        public E00Export(IFeatureWorkspace pTempWks, IFeatureLayer pFeatureLayer, IGeometry pFilterGeometry, string strFilter, bool blnClip, string strPath, string strE00FileName)
        {
            mTempWks = pTempWks;
            mFeatureLayer = pFeatureLayer;
            mFilterGeometry = pFilterGeometry;
            mStrFiter = strFilter;
            mBlnClip = blnClip;
            mStrPath = strPath;
            mStrE00FileName = strE00FileName;

        }
        public E00Export()
        {
        }
        public IFeatureLayer FeatureLayer
        {
            set
            {
                mFeatureLayer = value;
            }
        }

        public IGeometry FilterGeometry
        {
            set
            {
                mFilterGeometry = value;
            }
        }

        public string Filter
        {
            set
            {
                mStrFiter = value;
            }
        }
        public bool Clip
        {
            set
            {
                mBlnClip = value;
            }
        }

        public string Path
        {
            set
            {
                mStrPath = value;
            }
        }
        public string E00FileName
        {
            set
            {
                mStrE00FileName = value;
            }
        }
        public IFeatureWorkspace TempFeatureWorkspace
        {
            set
            {
                mTempWks = value;
            }
        }


        public bool Export()
        {
            if (mFeatureLayer == null) return false;
            try
            {
                DirectoryInfo pDirec = new DirectoryInfo(System.Windows.Forms.Application.StartupPath);
                pDirec.CreateSubdirectory("DitTempFolder");
                IFeatureClass pFcls = mFeatureLayer.FeatureClass;
                IFeatureWorkspace pFwks = ((IDataset)pFcls).Workspace as IFeatureWorkspace;
                if (mFilterGeometry != null)
                {
                    ISpatialFilter pSpatialFitler = new SpatialFilterClass();
                    pSpatialFitler.Geometry = mFilterGeometry;
                    pSpatialFitler.GeometryField = mFeatureLayer.FeatureClass.ShapeFieldName;
                    pSpatialFitler.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                    pSpatialFitler.WhereClause = mStrFiter;
                    if (FeatureLayerHasFeatures(mFeatureLayer, pSpatialFitler) == false) return false;
                    if (mBlnClip && pFcls.ShapeType != esriGeometryType.esriGeometryPoint & pFcls.FeatureType != esriFeatureType.esriFTAnnotation)
                    {
                        IFeatureClass pNewFcls = CreateFeatureClass(pFcls, mTempWks);

                        ClipFeatureClass(pFcls, pNewFcls, pSpatialFitler, mFilterGeometry);
                        ExpE00(((IDataset)pNewFcls).Workspace as IFeatureWorkspace, ((IDataset)pNewFcls).Name, pSpatialFitler, mStrPath);

                        try
                        {
                            ((IDataset)pNewFcls).Delete();
                        }
                        catch (Exception ex)
                        {
                            System.Windows.Forms.MessageBox.Show(ex.Message);
                        }
                        if (File.Exists(mStrPath + "\\" + ((IDataset)pNewFcls).Name + ".e00"))
                        {
                            File.Copy(mStrPath + "\\" + ((IDataset)pNewFcls).Name + ".e00", mStrPath + "\\" + mStrE00FileName + ".e00", true);
                            File.Delete(mStrPath + "\\" + ((IDataset)pNewFcls).Name + ".e00");
                        }
                    }
                    else
                    {
                        IFeatureLayerDefinition pFLayerDef = mFeatureLayer as IFeatureLayerDefinition;
                        if (pFLayerDef.DefinitionExpression == "" && pFLayerDef.DefinitionSelectionSet == null)
                        {
                            ExpE00(pFwks, ((IDataset)pFcls).Name, pSpatialFitler, mStrPath);
                        }
                        else  //the features in the featurelayer are a subset of features in the featureclass
                        {
                            IFeatureClass pNewFcls = CreateFeatureClass(pFcls, mTempWks);
                            CopyFeatures(pFcls, pNewFcls, pSpatialFitler);
                            if (pNewFcls.FeatureCount(null) == 0) return false;
                            ExpE00(pFwks, ((IDataset)pNewFcls).Name, pSpatialFitler, mStrPath);
                            try
                            {
                                ((IDataset)pNewFcls).Delete();
                            }
                            catch (System.Exception)
                            {
                            }
                            if (File.Exists(mStrPath + "\\" + ((IDataset)pNewFcls).Name + ".e00"))
                            {
                                File.Copy(mStrPath + "\\" + ((IDataset)pNewFcls).Name + ".e00", mStrPath + "\\" + mStrE00FileName + ".e00", true);
                                File.Delete(mStrPath + "\\" + ((IDataset)pNewFcls).Name + ".e00");
                            }
                        }
                    }
                }
                else
                {
                    IQueryFilter pFilter = new QueryFilterClass();
                    pFilter.WhereClause = mStrFiter;
                    IFeatureLayerDefinition pFLayerDef = mFeatureLayer as IFeatureLayerDefinition;
                    if (pFLayerDef.DefinitionExpression == "" && pFLayerDef.DefinitionSelectionSet == null)
                    {
                        if (pFcls.FeatureCount(pFilter) == 0) return false;
                        ExpE00(pFwks, ((IDataset)pFcls).Name, pFilter, mStrPath);
                    }
                    else
                    {
                        IFeatureClass pNewFcls = CreateFeatureClass(pFcls, mTempWks);
                        CopyFeatures(mFeatureLayer, pNewFcls, pFilter);
                        if (pNewFcls.FeatureCount(null) == 0) return false;
                        ExpE00(pFwks, ((IDataset)pNewFcls).Name, pFilter, mStrPath);
                        try
                        {
                            // Marshal.ReleaseComObject(pFwks);
                            // pFwks = null;
                            if (((IDataset)pNewFcls).CanDelete())
                            {
                                ((IFeatureWorkspaceManage)pFwks).DeleteByName(((IDataset)pNewFcls).FullName as IDatasetName);
                                ((IDataset)pNewFcls).Delete();
                            }

                        }
                        catch (System.Exception)
                        {
                        }
                        if (File.Exists(mStrPath + "\\" + ((IDataset)pNewFcls).Name + ".e00"))
                        {
                            File.Copy(mStrPath + "\\" + ((IDataset)pNewFcls).Name + ".e00", mStrPath + "\\" + mStrE00FileName + ".e00", true);
                            File.Delete(mStrPath + "\\" + ((IDataset)pNewFcls).Name + ".e00");
                        }
                    }
                }

                return true;
            }
            catch (System.Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 在指定条件下，图层上是否有要素
        /// </summary>
        /// <param name="pFeatureLayer"></param>
        /// <param name="pFilterGeometry"></param>
        /// <param name="strFilter"></param>
        /// <returns></returns>
        private bool FeatureLayerHasFeatures(IFeatureLayer pFeatureLayer, IQueryFilter pFilter)
        {
            IFeatureCursor pFcursor = pFeatureLayer.Search(pFilter, false);
            if (pFcursor == null) return false;
            IFeature pFeature = pFcursor.NextFeature();
            Marshal.ReleaseComObject(pFcursor);
            pFcursor = null;
            return pFeature != null;
        }

        /// <summary>
        /// create a new featureclass based on the template featureclass
        /// </summary>
        /// <param name="pTemplateFeatureClass"></param>
        /// <returns></returns>
        private IFeatureClass CreateFeatureClass(IFeatureClass pTemplateFeatureClass, IFeatureWorkspace pTargetWks)
        {
            try
            {
                IFeatureClass pNewFeatureClass;
                string strNewFclsName;
                string strTemplateFclsName = ((IDataset)pTemplateFeatureClass).Name;
                if ((((IDataset)pTemplateFeatureClass).Workspace).Type == esriWorkspaceType.esriRemoteDatabaseWorkspace && strTemplateFclsName.IndexOf(".") > 0)
                {
                    strTemplateFclsName = strTemplateFclsName.Substring(strTemplateFclsName.IndexOf(".") + 1);
                }

                IWorkspace2 pWks = pTargetWks as IWorkspace2;
                int index = 0;
                if (((IWorkspace)pTargetWks).Type != esriWorkspaceType.esriFileSystemWorkspace)
                {
                    while (true)
                    {
                        index++;
                        strNewFclsName = strTemplateFclsName + "_" + index;
                        if (pWks.get_NameExists(esriDatasetType.esriDTFeatureClass, strNewFclsName) == false)
                        {
                            break;
                        }
                    }
                }
                else
                {
                    while (true)
                    {
                        index++;
                        strNewFclsName = strTemplateFclsName + "_" + index;
                        if (System.IO.File.Exists(((IWorkspace)pTargetWks).PathName + "\\" + strNewFclsName + ".shp") == false)
                        {
                            break;
                        }
                    }
                }

                IClone pClone = pTemplateFeatureClass.Fields as IClone;
                if (pTemplateFeatureClass.FeatureType == esriFeatureType.esriFTAnnotation)
                {
                    IAnnotationClassExtension pAnnoFclsExtension = pTemplateFeatureClass.Extension as IAnnotationClassExtension;
                    pNewFeatureClass = com.zjgis.arcengineutility.GeodatabaseUtility.CreateAnnotationFeatCls(pTargetWks, null, strNewFclsName, pClone.Clone() as IFields, pAnnoFclsExtension.ReferenceScale);
                }
                else
                {
                    pNewFeatureClass = pTargetWks.CreateFeatureClass(strNewFclsName, pClone.Clone() as IFields, null, null, pTemplateFeatureClass.FeatureType, pTemplateFeatureClass.ShapeFieldName, "");
                    //IGeometryDefEdit pGeoDefEdit = pNewFeatureClass.Fields.get_Field(pNewFeatureClass.Fields.FindField(pNewFeatureClass.ShapeFieldName)).GeometryDef as IGeometryDefEdit;
                }
                return pNewFeatureClass;
                System.Windows.Forms.Application.DoEvents();
            }
            catch (System.Exception ex)
            {
                return null;
            }
        }

        private void CopyFeatures(IFeatureClass pSrcFcls, IFeatureClass pTargetFcls, IQueryFilter pFilter)
        {
            IFeatureCursor pTargetFCursor = null;
            IFeatureBuffer pFeatureBuffer;
            IFeatureCursor pFcursor = pSrcFcls.Search(pFilter, false);
            IFeature pFeature = pFcursor.NextFeature();
            if (pFeature == null) return;
            while (pFeature != null)
            {
                pTargetFCursor = pTargetFcls.Insert(true);
                pFeatureBuffer = pTargetFcls.CreateFeatureBuffer();

                if (pTargetFcls.FeatureType != esriFeatureType.esriFTAnnotation)
                {
                    pFeatureBuffer.Shape = pFeature.ShapeCopy;
                    for (int i = 0; i < pFeature.Fields.FieldCount; i++)
                    {
                        if (pFeatureBuffer.Fields.get_Field(i).Editable && pFeatureBuffer.Fields.get_Field(i).Type != esriFieldType.esriFieldTypeGeometry)
                            pFeatureBuffer.set_Value(i, pFeature.get_Value(i));
                    }
                }
                else
                {
                    pTargetFCursor = pTargetFcls.Insert(true);
                    pFeatureBuffer = pTargetFcls.CreateFeatureBuffer();
                    IAnnotationFeature pSrcAnnoFeature = pFeature as IAnnotationFeature;
                    IAnnotationFeature pTargetAnnoFeature = pFeatureBuffer as IAnnotationFeature;
                    ITextElement pTxtElement = new TextElementClass();
                    pTxtElement.Text = ((ITextElement)pSrcAnnoFeature.Annotation).Text;
                    IElement pElement = pTxtElement as IElement;
                    pElement.Geometry = pFeature.Shape.Envelope.LowerLeft;
                    pTxtElement.Symbol = ((ITextElement)pSrcAnnoFeature.Annotation).Symbol;
                    pTxtElement.Symbol.HorizontalAlignment = esriTextHorizontalAlignment.esriTHACenter;
                    pTxtElement.Symbol.VerticalAlignment = esriTextVerticalAlignment.esriTVACenter;
                    pTargetAnnoFeature.Annotation = pTxtElement as IElement;
                    pTargetFCursor.InsertFeature(pFeatureBuffer);
                }

                pTargetFCursor.InsertFeature(pFeatureBuffer);
                pFeature = pFcursor.NextFeature();
            }
            System.Windows.Forms.Application.DoEvents();
            Marshal.ReleaseComObject(pFcursor);
            pFcursor = null;
            Marshal.ReleaseComObject(pTargetFCursor);
            pTargetFCursor = null;
            pTargetFCursor.Flush();
        }
        private void CopyFeatures(IFeatureLayer pSrcFeatureLayer, IFeatureClass pTargetFcls, IQueryFilter pFilter)
        {
            IFeatureCursor pTargetFCursor = null;
            IFeatureBuffer pFeatureBuffer;
            IFeatureCursor pFcursor = pSrcFeatureLayer.Search(pFilter, false);
            IFeature pFeature = pFcursor.NextFeature();
            if (pFeature == null) return;
            while (pFeature != null)
            {
                pTargetFCursor = pTargetFcls.Insert(true);
                pFeatureBuffer = pTargetFcls.CreateFeatureBuffer();

                pFeatureBuffer.Shape = pFeature.ShapeCopy;
                for (int i = 0; i < pFeature.Fields.FieldCount; i++)
                {
                    if (pFeatureBuffer.Fields.get_Field(i).Editable && pFeatureBuffer.Fields.get_Field(i).Type != esriFieldType.esriFieldTypeGeometry)
                        pFeatureBuffer.set_Value(i, pFeature.get_Value(i));
                }

                pTargetFCursor.InsertFeature(pFeatureBuffer);
                pFeature = pFcursor.NextFeature();
            }
            pTargetFCursor.Flush();
            System.Windows.Forms.Application.DoEvents();
            Marshal.ReleaseComObject(pFcursor);
            pFcursor = null;
            Marshal.ReleaseComObject(pTargetFCursor);
            pTargetFCursor = null;

        }
        private void ClipFeatureClass(IFeatureClass pSrcFcls, IFeatureClass pTargetFcls, IQueryFilter pFilter, IGeometry pClipGeometry)
        {
            try
            {
                IFeatureCursor pTargetFCursor = null;
                IFeatureBuffer pFeatureBuffer;
                IFeatureCursor pFcursor = pSrcFcls.Search(pFilter, false);
                IFeature pFeature = pFcursor.NextFeature();
                if (pFeature == null) return;

                ITopologicalOperator2 pTopoOp;
                IRelationalOperator pRelOp;
                pTopoOp = pClipGeometry as ITopologicalOperator2;
                pTopoOp.IsKnownSimple_2 = false;
                pTopoOp.Simplify();
                pRelOp = pClipGeometry as IRelationalOperator;
                IGeometry pNewGeometry;
                IField pGeometryFld = pSrcFcls.Fields.get_Field(pSrcFcls.FindField(pSrcFcls.ShapeFieldName));
                IGeometryDef pGeometryDef = pGeometryFld.GeometryDef;
                while (pFeature != null)
                {
                    pTargetFCursor = pTargetFcls.Insert(true);
                    pFeatureBuffer = pTargetFcls.CreateFeatureBuffer();
                    IGeometry pGeo = pFeature.ShapeCopy;
                    ITopologicalOperator2 pTopoOp2 = pGeo as ITopologicalOperator2;
                    pTopoOp2.IsKnownSimple_2 = false;
                    pTopoOp2.Simplify();
                    if (pClipGeometry.SpatialReference.Equals(pGeo.SpatialReference) == false)
                    {
                        pClipGeometry.Project(pGeo.SpatialReference);
                    }
                    if (pRelOp.Overlaps(pGeo) || pRelOp.Crosses(pGeo) || pRelOp.Within(pGeo))
                    {
                        pNewGeometry = pTopoOp.Intersect(pGeo, pGeo.Dimension);
                        pNewGeometry.SpatialReference = pGeo.SpatialReference;
                        if (HasZ(pTargetFcls)) UpdateGeometryZ(pNewGeometry, 0);
                        pFeatureBuffer.Shape = pNewGeometry;
                    }
                    else
                    {
                        pFeatureBuffer.Shape = pFeature.ShapeCopy;
                    }
                    for (int i = 0; i < pFeature.Fields.FieldCount; i++)
                    {
                        if (pFeatureBuffer.Fields.get_Field(i).Editable && pFeatureBuffer.Fields.get_Field(i).Type != esriFieldType.esriFieldTypeGeometry)
                            pFeatureBuffer.set_Value(i, pFeature.get_Value(i));
                    }
                    pTargetFCursor.InsertFeature(pFeatureBuffer);
                    pFeature = pFcursor.NextFeature();
                }

                pTargetFCursor.Flush();
                System.Windows.Forms.Application.DoEvents();

                Marshal.ReleaseComObject(pFcursor);
                pFcursor = null;
                Marshal.ReleaseComObject(pTargetFCursor);
                pTargetFCursor = null;
            }
            catch (System.Exception)
            {
            }

        }


        private bool HasZ(IFeatureClass pFcls)
        {
            IField pFld = pFcls.Fields.get_Field(pFcls.FindField(pFcls.ShapeFieldName));
            IGeometryDef pGeometryDef = pFld.GeometryDef;
            return pGeometryDef.HasZ;
        }

        private void UpdateGeometryZ(IGeometry pGeometry, double dblZ)
        {
            IZAware pZArare = pGeometry as IZAware;
            pZArare.ZAware = true;
            IZ pZ = pGeometry as IZ;
            if (pZ != null) pZ.SetConstantZ(dblZ);

        }
    }
}
